package com.lechicanh.cgrid.ke.handler.service;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Logger;

import com.lechicanh.cgrid.ke.api.job.Job;
import com.lechicanh.cgrid.ke.api.message.Message;
import com.lechicanh.cgrid.ke.api.resource.Resource;
import com.lechicanh.cgrid.ke.api.service.HandlerService;
import com.lechicanh.cgrid.ke.handler.registry.WorkerRegistry;
import com.lechicanh.cgrid.ke.handler.registry.WorkerRegistryImpl;

public class HandlerServiceImpl extends UnicastRemoteObject implements HandlerService {
	private static final long serialVersionUID = 1001L;
	private static final Logger m_logger = Logger.getLogger(HandlerServiceImpl.class.getSimpleName());
	private static final int DEFAULT_PAGE_PER_JOB = 5;
	private static final int DEFAULT_FROM_PAGE = 10;
	private static final int DEFAULT_TO_PAGE = 1;
	private static final String OUTPUT = "output.txt";
	private WorkerRegistry m_registry;
	
	private long m_initFromPage;
	private long m_fromPage;
	private long m_toPage;
	private int m_pagePerJob;
	
	private boolean m_done = false;
	private boolean m_begin = true;
	
	private Long m_timeStart;
	private Long m_timeEnd;
	
	private List<Long> m_wattingJob = new ArrayList<Long>();
	
	public HandlerServiceImpl() throws RemoteException {
		this(DEFAULT_FROM_PAGE, DEFAULT_TO_PAGE);
	}
	
	public HandlerServiceImpl(long fromPage, long toPage) throws RemoteException {
		this(fromPage, toPage, DEFAULT_PAGE_PER_JOB);
	}
	
	public HandlerServiceImpl(long fromPage, long toPage, int pagePerJob) throws RemoteException {
		m_initFromPage = fromPage;
		m_fromPage = fromPage;
		m_toPage = toPage;
		m_pagePerJob = pagePerJob;
		m_registry = new WorkerRegistryImpl();
		BufferedWriter writer = null;
		try {
			writer = new BufferedWriter(new FileWriter(OUTPUT));
		} catch (IOException e) {
			
		}finally{
			try {
				writer.close();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		}
	}
	
	@Override
	public synchronized void message(Message mess) throws RemoteException {
		System.out.println("Worker " + mess.getSender() +" sends message " + mess.getMessage() + ".");
		if(Resource.DONE_JOB_MESSAGE.equals(mess.getMessage())){
			m_wattingJob.remove(mess.getId());
			BufferedWriter writer = null;
			try {
				writer = new BufferedWriter(new FileWriter(OUTPUT, true));
				List<String> list = (List<String>)mess.getAttachment();
				Iterator<String> i = list.iterator();
				while(i.hasNext()){
					try {
						writer.write(i.next());
						writer.write("\n");
					} catch (IOException e) {
						throw new RuntimeException(e);
					}
				 }
			} catch (IOException e) {
				throw new RuntimeException(e);
			}finally{
				try {
					writer.close();
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			
			
		}
	}
	
	private void showUpDone(){
		m_timeEnd = System.currentTimeMillis();
		System.out.println("Extracting is done with result in " + OUTPUT);
		System.out.println("Tooks: " +( m_timeEnd - m_timeStart)/1000 + "s");
		System.out.println("End the grid, closing hanlder");
		System.exit(0);
	}
	
	private void begin(){
		m_timeStart = System.currentTimeMillis();
	}
	
	@Override
	public synchronized Job free(String identifier) throws RemoteException{
		if(!m_registry.isRegistered(identifier)){
			return new Job("handlerService", identifier, null, Resource.NOT_REGITERED_MESSAGE);
		}
		
		if(m_begin){
			m_begin = false;
			begin();
		}
		
		System.out.println("Worker " + identifier + " is free.");
		
		String message = Resource.NO_JOB_MESSAGE;
		
		long fromPageJob = m_fromPage;
		long toPageJob = m_fromPage + m_pagePerJob;
		long jobId = -1;
		long remaining = 0;
		
		if(m_done && m_wattingJob.isEmpty()){
			showUpDone();
		}
		
		if(!m_done){
			
			message = Resource.NEW_JOB_MESSAGE;
			remaining = m_toPage - m_fromPage; 
			
			if(remaining < m_pagePerJob){
				toPageJob = m_toPage;
				m_fromPage = m_toPage;
			}else if(remaining == m_pagePerJob){
				toPageJob = m_toPage;
				m_fromPage = m_toPage;
			}else{
				toPageJob = m_fromPage + m_pagePerJob - 1;
				m_fromPage += m_pagePerJob;
			}
			
			jobId = toPageJob;
		}
		
		if(jobId != -1){
			m_wattingJob.add(jobId);
		}
		Job job = new Job("handlerService", identifier, jobId, message, fromPageJob, toPageJob);
		
		System.out.println("Sent " + identifier + " new job");
		
		if(m_toPage - m_fromPage == 0){
			m_done = true;
		}
		
		return job;
	}
	@Override
	public synchronized void register(String identifier) throws RemoteException {
		System.out.println("Worker joins the grid network with name: " + identifier);
		m_registry.register(identifier);
	}

}
